#include <iostream>
#include <assert.h>
#include <Kernels.h>
#include <Defines.h>
#include <TimeDiff.h>
#include <MallocAlign.h>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
using namespace std;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SpMVRecursionKernelQTS( const U32 _lvl, const U32 _m, const U32 _n, const U64 _node, const U64 * _nodes, const double * _x, double * _y, const U64 _pos ) {
   
   const U32 pmin = 0x80000000;
   const U32 mask = 0xFFFFFFFF;
   const U32 pmsk = pmin - 1;
   
   const U32 rval = _node & mask;
   const U32 lval = ( _node >> 32 ) & mask;
   if( _lvl > 0 ) {
      // not a leaf
      const bool filled = lval < pmin;
      if( filled ) {
         const U64 lchild = _nodes[ lval ];
         const U64 rchild = _nodes[ rval ];
         U32 lvl = _lvl - 1;
         if( lval ) { SpMVRecursionKernelQTS( lvl, _m, _n, lchild, _nodes, _x, _y, _pos                      ); }
         if( rval ) { SpMVRecursionKernelQTS( lvl, _m, _n, rchild, _nodes, _x, _y, _pos + (1ULL<<((U64)lvl)) ); }
      }
      else {
         // path compaction detected
         U32   lvl = _lvl;
         U64   pos = _pos;
         U32   ptr = lval & pmsk;
         U32  path = rval;
         U64 child = _nodes[ ptr ];
         while( path > 1 ) {
            lvl--;
            if( path & 1 ) {
               pos += ( 1ULL << ((U64)lvl) );
            }
            path >>= 1;
         }
         SpMVRecursionKernelQTS( lvl, _m, _n, child, _nodes, _x, _y, pos );
      }
   }
   else {
      // leaf node
      USD64 v;
      v.u = _node;
      if( v.u != 0ULL ) {
         U32 r = Pos2Row( _pos, _m, _n );
         U32 c = Pos2Col( _pos, _m, _n );
         #ifdef __SPMV__
         _y[r] += _x[c] * v.d;
         #else
         assert( false );
         std::cout << SETDEC( 0 ) << r << " " << SETDEC(0) << c << " " << SETSCI( 20 ) << v.d << std::endl;
         #endif
      }
   }
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SpMVFlatKernelCOO_HL2_final( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0, const U32 _nnzIdx1, const U32 _rcaIdx1, const double * _x, double * _y, timespec * clks ) {
   DEBUG_PRINT( "entering kernel... hello :)" );   
   DEBUG_PRINT( "_hgt = " << _hgt );
   
   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   U32 pnnzStack0[ numAlloc ];
   U32 pnnzStack1[ numAlloc ];
   U32 prcaStack0[ numAlloc ];
   U32 prcaStack1[ numAlloc ];
   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 c0 = 0;
   U32 nnzLval0;
   U32 nnzRval0;

   U32 r1 = 0;
   U32 c1 = 0;
   U32 nnzLval1 = 1;
   U32 nnzRval1;
   
   S32 rcaLval0;
   S32 rcaRval0;

   S32 rcaLval1;
   S32 rcaRval1;
   
   U32 sp = 1;
   U32 lvl  = _hgt;
   
   U64 nnzNode0;
   U64 rcaNode0;

   U64 nnzNode1;
   U64 rcaNode1;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
      pnnzStack1[ ii ] = 0;
      prcaStack1[ ii ] = 0;
   }
   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;
   pnnzStack1[ 0 ] = _nnzIdx1;
   prcaStack1[ 0 ] = _rcaIdx1;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp && nnzLval1 ) {
      sp--;
      DEBUG_PRINT( "Top of both loop, sp = " << sp );
      DEBUG_PRINT( "lvl = " << lvl );
      
      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];

      nnzNode1 = _nodes[ pnnzStack1[sp] ];
      rcaNode1 = _nodes[ prcaStack1[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;

      rcaRval1 = rcaNode1 & mask;
      rcaLval1 = ( rcaNode1 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;

         nnzRval1 = nnzNode1 & mask;
         nnzLval1 = ( nnzNode1 >> 32 ) & mask;
      
         lvl--;
         
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzRval0;
         prcaStack0[sp] = rcaRval0;
                      
         pnnzStack1[sp] = nnzRval1;
         prcaStack1[sp] = rcaRval1;
         sp++;
         
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzLval0;
         prcaStack0[sp] = rcaLval0;
                      
         pnnzStack1[sp] = nnzLval1;
         prcaStack1[sp] = rcaLval1;
         sp++;
      }
      else  {
         // leaf node
         DEBUG_PRINT( "Leaf branch0, Leaf branch1" );
         USD64 v0;
         USD64 v1;
         v0.u = nnzNode0;
         v1.u = nnzNode1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "r1 = " << r1 << ", c1 = " << c1 );
         DEBUG_PRINT( "rcaLval0 = " << rcaLval0 );
         DEBUG_PRINT( "rcaRval0 = " << rcaRval0 );
         DEBUG_PRINT( "rcaLval1 = " << rcaLval1 );
         DEBUG_PRINT( "rcaRval1 = " << rcaRval1 );
         DEBUG_PRINT( "v0.u = " << v0.u );
         DEBUG_PRINT( "v1.u = " << v1.u );
         DEBUG_PRINT( "v0.d = " << v0.d );
         DEBUG_PRINT( "v1.d = " << v1.d );
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         r1 += rcaLval1 + 1;
         c1 += rcaRval1 + 1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "r1 = " << r1 << ", c1 = " << c1 );
         _y[r0] += v0.d * _x[c0];
         _y[r1] += v1.d * _x[c1];
      }
   }
   DEBUG_PRINT( "Fell through both loop." );

   while( sp ) {
      sp--;
      
      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;
      
         lvl--;
         if( nnzRval0 ) {
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzRval0;
            prcaStack0[sp] = rcaRval0;
            sp++;
         }
         if( nnzLval0 ) {
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzLval0;
            prcaStack0[sp] = rcaLval0;
            sp++;
         }
      }
      else  {
         // leaf node
         USD64 v0;
         v0.u = nnzNode0;
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         _y[r0] += v0.d * _x[c0];
      }
   }
      
   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving kernel... goodbye :)" );
}
void SpMVFlatKernelCOO( const U32 _hgt,  const U64 * _nodes, const double * _x, double * _y, timespec * clks ) {

   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   U32 pnnzStack[ numAlloc ];
   U32 prcaStack[ numAlloc ];
   const U32 mask = 0xFFFFFFFF;

   U32 r = 0;
   U32 c = 0;
   U32 nnzLval;
   U32 nnzRval;
   
   S32 rcaLval;
   S32 rcaRval;
   
   U32 sp   = 1; // stack-ptr
   U32 lvl  = _hgt;
   
   U64 nnzNode;
   U64 rcaNode;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack[ ii ] = 0;
      prcaStack[ ii ] = 0;
   }
   pnnzStack[ 0 ] = _nodes[ 1 ];
   prcaStack[ 0 ] = _nodes[ 2 ];

   clock_gettime( CLOCK_MONOTONIC, clks   );


   while( sp ) {
      sp--;
      
      lvl = lvlStack[ sp ];
      nnzNode = _nodes[ pnnzStack[sp] ];
      rcaNode = _nodes[ prcaStack[sp] ];
      
      rcaRval = rcaNode & mask;
      rcaLval = ( rcaNode >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         nnzRval = nnzNode & mask;
         nnzLval = ( nnzNode >> 32 ) & mask;
      
         lvl--;
         if( nnzRval ) {
            lvlStack[sp] = lvl;
            pnnzStack[sp] = nnzRval;
            prcaStack[sp] = rcaRval;
            sp++;
         }
         if( nnzLval ) {
            lvlStack[sp] = lvl;
            pnnzStack[sp] = nnzLval;
            prcaStack[sp] = rcaLval;
            sp++;
         }
      }
      else {
         // leaf node
         USD64 v;
         v.u = nnzNode;
         r += rcaLval + 1;
         c += rcaRval + 1;
         _y[r] += v.d * _x[c];
      }
   }

   clock_gettime( CLOCK_MONOTONIC, clks+1 );
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SpMVFlatKernelCOO_HL0( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0, const double * _x, double * _y, timespec * clks ) {
   DEBUG_PRINT( "entering SpMVFlatKernelCOO_HL0() " );   
   DEBUG_PRINT( "_hgt = " << _hgt );
   
   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   U32 pnnzStack0[ numAlloc ];
   U32 prcaStack0[ numAlloc ];
   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 c0 = 0;
   U32 nnzLval0;
   U32 nnzRval0;
   
   S32 rcaLval0;
   S32 rcaRval0;

   DEBUG_PRINT( "setting sp to 1" );
   U32 sp = 1;
   U32 lvl = _hgt;
      
   U64 nnzNode0;
   U64 rcaNode0;
   
   // must init ptr stack to zero
   DEBUG_PRINT( "initializing stacks" );
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
   }
   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp ) {
      sp--;
      DEBUG_PRINT( "Top of loop, sp = " << sp << ", lvl = " << lvl );

      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;
      
         lvl--;
         if( true || nnzRval0 ) {
            // DEBUG_PRINT( "Found nnzRval0" );
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzRval0;
            prcaStack0[sp] = rcaRval0;
            sp++;
         }
         if( true || nnzLval0 ) {
            // DEBUG_PRINT( "Found nnzLval0" );
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzLval0;
            prcaStack0[sp] = rcaLval0;
            sp++;
         }
      }
      else {
         // leaf node
         DEBUG_PRINT( "Leaf node" );
         USD64 v0;
         v0.u = nnzNode0;
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "" );
         _y[r0] += v0.d * _x[c0];
      }
   }
   
   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving SpMVFlatKernelCOO_HL2() " );
}
void SpMVFlatKernelCOO_HL2( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0,
                                                                const U32 _nnzIdx1, const U32 _rcaIdx1,
                                                                const double * _x, double * _y, timespec * clks )
{
   DEBUG_PRINT( "entering SpMVFlatKernelCOO_HL2() " );   
   DEBUG_PRINT( "_hgt = " << _hgt );
   //const U8 incTable[] = { 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
   const U8 incTable[] = { 8, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 };
   const U64 numAlloc = 40;

   U32 leafIdx = 0;
   U32 pnnzStack0[ numAlloc ];
   U32 pnnzStack1[ numAlloc ];
   U32 prcaStack0[ numAlloc ];
   U32 prcaStack1[ numAlloc ];
   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 c0 = 0;
   U32 nnzLval0;
   U32 nnzRval0;

   U32 r1 = 0;
   U32 c1 = 0;
   U32 nnzLval1;
   U32 nnzRval1;
   
   S32 rcaLval0;
   S32 rcaRval0;

   S32 rcaLval1;
   S32 rcaRval1;
   
   U32 sp = 1;
   U32 lvl = _hgt;
      
   U64 nnzNode0;
   U64 rcaNode0;

   U64 nnzNode1;
   U64 rcaNode1;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      //lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
      pnnzStack1[ ii ] = 0;
      prcaStack1[ ii ] = 0;
   }
   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;
   pnnzStack1[ 0 ] = _nnzIdx1;
   prcaStack1[ 0 ] = _rcaIdx1;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp ) {
      sp--;
      
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];

      nnzNode1 = _nodes[ pnnzStack1[sp] ];
      rcaNode1 = _nodes[ prcaStack1[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;

      rcaRval1 = rcaNode1 & mask;
      rcaLval1 = ( rcaNode1 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;

         nnzRval1 = nnzNode1 & mask;
         nnzLval1 = ( nnzNode1 >> 32 ) & mask;
      
         lvl--;
         if( true || nnzRval0 || nnzRval1 ) {
            // DEBUG_PRINT( "Found nnzRval0" );
            //lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzRval0;
            prcaStack0[sp] = rcaRval0;
            pnnzStack1[sp] = nnzRval1;
            prcaStack1[sp] = rcaRval1;
            sp++;
         }
         if( true || nnzLval0 || nnzLval1) {
            // DEBUG_PRINT( "Found nnzLval0" );
            //lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzLval0;
            prcaStack0[sp] = rcaLval0;
            pnnzStack1[sp] = nnzLval1;
            prcaStack1[sp] = rcaLval1;
            sp++;
         }
      }
      else {
         // leaf node
         lvl = 0;
         leafIdx++;
         U32 mli = leafIdx & 0xFF;
         lvl = incTable[ mli ];

         USD64 v0;
         USD64 v1;
         v0.u = nnzNode0;
         v1.u = nnzNode1;

         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         r1 += rcaLval1 + 1;
         c1 += rcaRval1 + 1;

         _y[r0] += v0.d * _x[c0];
         _y[r1] += v1.d * _x[c1];

         if( lvl == 8 ) {
            mli = 0xFF & ( leafIdx >> 8 );
            lvl += incTable[ mli ];
            if( lvl == 16 ) {
               mli = 0xFF & ( leafIdx >> 16 );
               lvl += incTable[ mli ];
            }
         }
      }
   }

   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving SpMVFlatKernelCOO_HL2() " );
}
void SpMVFlatKernelCOO_HL4( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0,
                                                                const U32 _nnzIdx1, const U32 _rcaIdx1,
                                                                const U32 _nnzIdx2, const U32 _rcaIdx2,
                                                                const U32 _nnzIdx3, const U32 _rcaIdx3,
                                                                const double * _x, double * _y, timespec * clks )
{
   DEBUG_PRINT( "entering SpMVFlatKernelCOO_HL4() " );   
   DEBUG_PRINT( "_hgt = " << _hgt );
   
   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   U32 pnnzStack0[ numAlloc ];
   U32 pnnzStack1[ numAlloc ];
   U32 pnnzStack2[ numAlloc ];
   U32 pnnzStack3[ numAlloc ];
   U32 prcaStack0[ numAlloc ];
   U32 prcaStack1[ numAlloc ];
   U32 prcaStack2[ numAlloc ];
   U32 prcaStack3[ numAlloc ];   
   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 r1 = 0;
   U32 r2 = 0;
   U32 r3 = 0;
      
   U32 c0 = 0;
   U32 c1 = 0;
   U32 c2 = 0;
   U32 c3 = 0;
   
   U32 nnzLval0;
   U32 nnzRval0;
   U32 nnzLval1;
   U32 nnzRval1;
   U32 nnzLval2;
   U32 nnzRval2;
   U32 nnzLval3;
   U32 nnzRval3;
   
   S32 rcaLval0;
   S32 rcaRval0;
   S32 rcaLval1;
   S32 rcaRval1;
   S32 rcaLval2;
   S32 rcaRval2;
   S32 rcaLval3;
   S32 rcaRval3;
   
   U32 sp = 1;
   U32 lvl = _hgt;
      
   U64 nnzNode0;
   U64 rcaNode0;
   U64 nnzNode1;
   U64 rcaNode1;
   U64 nnzNode2;
   U64 rcaNode2;
   U64 nnzNode3;
   U64 rcaNode3;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
      pnnzStack1[ ii ] = 0;
      prcaStack1[ ii ] = 0;
      pnnzStack2[ ii ] = 0;
      prcaStack2[ ii ] = 0;
      pnnzStack3[ ii ] = 0;
      prcaStack3[ ii ] = 0;
   }
   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;
   pnnzStack1[ 0 ] = _nnzIdx1;
   prcaStack1[ 0 ] = _rcaIdx1;
   pnnzStack2[ 0 ] = _nnzIdx2;
   prcaStack2[ 0 ] = _rcaIdx2;
   pnnzStack3[ 0 ] = _nnzIdx3;
   prcaStack3[ 0 ] = _rcaIdx3;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp ) {
      
      sp--;
      DEBUG_PRINT( "Top of loop, sp = " << sp << ", lvl = " << lvl );

      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];
      nnzNode1 = _nodes[ pnnzStack1[sp] ];
      rcaNode1 = _nodes[ prcaStack1[sp] ];
      nnzNode2 = _nodes[ pnnzStack2[sp] ];
      rcaNode2 = _nodes[ prcaStack2[sp] ];
      nnzNode3 = _nodes[ pnnzStack3[sp] ];
      rcaNode3 = _nodes[ prcaStack3[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;

      rcaRval1 = rcaNode1 & mask;
      rcaLval1 = ( rcaNode1 >> 32 ) & mask;

      rcaRval2 = rcaNode2 & mask;
      rcaLval2 = ( rcaNode2 >> 32 ) & mask;

      rcaRval3 = rcaNode3 & mask;
      rcaLval3 = ( rcaNode3 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;

         nnzRval1 = nnzNode1 & mask;
         nnzLval1 = ( nnzNode1 >> 32 ) & mask;

         nnzRval2 = nnzNode2 & mask;
         nnzLval2 = ( nnzNode2 >> 32 ) & mask;

         nnzRval3 = nnzNode3 & mask;
         nnzLval3 = ( nnzNode3 >> 32 ) & mask;
      
         lvl--;
         if( true || nnzRval0 || nnzRval1 || nnzRval2 || nnzRval3 ) {
            // DEBUG_PRINT( "Found nnzRval0" );
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzRval0;
            prcaStack0[sp] = rcaRval0;
            pnnzStack1[sp] = nnzRval1;
            prcaStack1[sp] = rcaRval1;
            pnnzStack2[sp] = nnzRval2;
            prcaStack2[sp] = rcaRval2;
            pnnzStack3[sp] = nnzRval3;
            prcaStack3[sp] = rcaRval3;
            sp++;
         }
         if( true || nnzLval0 || nnzLval1 || nnzLval2 || nnzLval3 ) {
            // DEBUG_PRINT( "Found nnzLval0" );
            lvlStack[sp] = lvl;
            pnnzStack0[sp] = nnzLval0;
            prcaStack0[sp] = rcaLval0;
            pnnzStack1[sp] = nnzLval1;
            prcaStack1[sp] = rcaLval1;
            pnnzStack2[sp] = nnzLval2;
            prcaStack2[sp] = rcaLval2;
            pnnzStack3[sp] = nnzLval3;
            prcaStack3[sp] = rcaLval3;
            sp++;
         }
      }
      else {
         // leaf node
         DEBUG_PRINT( "Leaf node" );
         USD64 v0;
         USD64 v1;
         USD64 v2;
         USD64 v3;
         v0.u = nnzNode0;
         v1.u = nnzNode1;
         v2.u = nnzNode2;
         v3.u = nnzNode3;
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         r1 += rcaLval1 + 1;
         c1 += rcaRval1 + 1;
         r2 += rcaLval2 + 1;
         c2 += rcaRval2 + 1;
         r3 += rcaLval3 + 1;
         c3 += rcaRval3 + 1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "r1 = " << r1 << ", c1 = " << c1 );
         DEBUG_PRINT( "" );
         _y[r0] += v0.d * _x[c0];
         _y[r1] += v1.d * _x[c1];
         _y[r2] += v2.d * _x[c2];
         _y[r3] += v3.d * _x[c3];
      }
   }
   
   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving SpMVFlatKernelCOO_HL4() " );
}
void SpMVFlatKernelCOO_HL8( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0, 
                                                                const U32 _nnzIdx1, const U32 _rcaIdx1,
                                                                const U32 _nnzIdx2, const U32 _rcaIdx2,
                                                                const U32 _nnzIdx3, const U32 _rcaIdx3,
                                                                const U32 _nnzIdx4, const U32 _rcaIdx4,
                                                                const U32 _nnzIdx5, const U32 _rcaIdx5,
                                                                const U32 _nnzIdx6, const U32 _rcaIdx6,
                                                                const U32 _nnzIdx7, const U32 _rcaIdx7,
                                                                const double * _x, double * _y, timespec * clks )
{
   DEBUG_PRINT( "entering SpMVFlatKernelCOO_HL8() " );   
   DEBUG_PRINT( "_hgt = " << _hgt );
   
   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   
   U32 pnnzStack0[ numAlloc ];
   U32 pnnzStack1[ numAlloc ];
   U32 pnnzStack2[ numAlloc ];
   U32 pnnzStack3[ numAlloc ];
   U32 pnnzStack4[ numAlloc ];
   U32 pnnzStack5[ numAlloc ];
   U32 pnnzStack6[ numAlloc ];
   U32 pnnzStack7[ numAlloc ];

   U32 prcaStack0[ numAlloc ];
   U32 prcaStack1[ numAlloc ];
   U32 prcaStack2[ numAlloc ];
   U32 prcaStack3[ numAlloc ];   
   U32 prcaStack4[ numAlloc ];
   U32 prcaStack5[ numAlloc ];
   U32 prcaStack6[ numAlloc ];
   U32 prcaStack7[ numAlloc ];   

   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 r1 = 0;
   U32 r2 = 0;
   U32 r3 = 0;
   U32 r4 = 0;
   U32 r5 = 0;
   U32 r6 = 0;
   U32 r7 = 0;
      
   U32 c0 = 0;
   U32 c1 = 0;
   U32 c2 = 0;
   U32 c3 = 0;
   U32 c4 = 0;
   U32 c5 = 0;
   U32 c6 = 0;
   U32 c7 = 0;
   
   U32 nnzLval0;
   U32 nnzRval0;
   U32 nnzLval1;
   U32 nnzRval1;
   U32 nnzLval2;
   U32 nnzRval2;
   U32 nnzLval3;
   U32 nnzRval3;
   U32 nnzLval4;
   U32 nnzRval4;
   U32 nnzLval5;
   U32 nnzRval5;
   U32 nnzLval6;
   U32 nnzRval6;
   U32 nnzLval7;
   U32 nnzRval7;
   
   S32 rcaLval0;
   S32 rcaRval0;
   S32 rcaLval1;
   S32 rcaRval1;
   S32 rcaLval2;
   S32 rcaRval2;
   S32 rcaLval3;
   S32 rcaRval3;
   S32 rcaLval4;
   S32 rcaRval4;
   S32 rcaLval5;
   S32 rcaRval5;
   S32 rcaLval6;
   S32 rcaRval6;
   S32 rcaLval7;
   S32 rcaRval7;
   
   U32 sp = 1;
   U32 lvl = _hgt;
      
   U64 nnzNode0;
   U64 rcaNode0;
   U64 nnzNode1;
   U64 rcaNode1;
   U64 nnzNode2;
   U64 rcaNode2;
   U64 nnzNode3;
   U64 rcaNode3;
   U64 nnzNode4;
   U64 rcaNode4;
   U64 nnzNode5;
   U64 rcaNode5;
   U64 nnzNode6;
   U64 rcaNode6;
   U64 nnzNode7;
   U64 rcaNode7;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
      pnnzStack1[ ii ] = 0;
      prcaStack1[ ii ] = 0;
      pnnzStack2[ ii ] = 0;
      prcaStack2[ ii ] = 0;
      pnnzStack3[ ii ] = 0;
      prcaStack3[ ii ] = 0;
      pnnzStack4[ ii ] = 0;
      prcaStack4[ ii ] = 0;
      pnnzStack5[ ii ] = 0;
      prcaStack5[ ii ] = 0;
      pnnzStack6[ ii ] = 0;
      prcaStack6[ ii ] = 0;
      pnnzStack7[ ii ] = 0;
      prcaStack7[ ii ] = 0;
   }
   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;
   pnnzStack1[ 0 ] = _nnzIdx1;
   prcaStack1[ 0 ] = _rcaIdx1;
   pnnzStack2[ 0 ] = _nnzIdx2;
   prcaStack2[ 0 ] = _rcaIdx2;
   pnnzStack3[ 0 ] = _nnzIdx3;
   prcaStack3[ 0 ] = _rcaIdx3;
   pnnzStack4[ 0 ] = _nnzIdx4;
   prcaStack4[ 0 ] = _rcaIdx4;
   pnnzStack5[ 0 ] = _nnzIdx5;
   prcaStack5[ 0 ] = _rcaIdx5;
   pnnzStack6[ 0 ] = _nnzIdx6;
   prcaStack6[ 0 ] = _rcaIdx6;
   pnnzStack7[ 0 ] = _nnzIdx7;
   prcaStack7[ 0 ] = _rcaIdx7;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp ) {
      
      sp--;
      DEBUG_PRINT( "Top of loop, sp = " << sp << ", lvl = " << lvl );

      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];
      nnzNode1 = _nodes[ pnnzStack1[sp] ];
      rcaNode1 = _nodes[ prcaStack1[sp] ];
      nnzNode2 = _nodes[ pnnzStack2[sp] ];
      rcaNode2 = _nodes[ prcaStack2[sp] ];
      nnzNode3 = _nodes[ pnnzStack3[sp] ];
      rcaNode3 = _nodes[ prcaStack3[sp] ];
      nnzNode4 = _nodes[ pnnzStack4[sp] ];
      rcaNode4 = _nodes[ prcaStack4[sp] ];
      nnzNode5 = _nodes[ pnnzStack5[sp] ];
      rcaNode5 = _nodes[ prcaStack5[sp] ];
      nnzNode6 = _nodes[ pnnzStack6[sp] ];
      rcaNode6 = _nodes[ prcaStack6[sp] ];
      nnzNode7 = _nodes[ pnnzStack7[sp] ];
      rcaNode7 = _nodes[ prcaStack7[sp] ];
      
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;

      rcaRval1 = rcaNode1 & mask;
      rcaLval1 = ( rcaNode1 >> 32 ) & mask;

      rcaRval2 = rcaNode2 & mask;
      rcaLval2 = ( rcaNode2 >> 32 ) & mask;

      rcaRval3 = rcaNode3 & mask;
      rcaLval3 = ( rcaNode3 >> 32 ) & mask;

      rcaRval4 = rcaNode4 & mask;
      rcaLval4 = ( rcaNode4 >> 32 ) & mask;

      rcaRval5 = rcaNode5 & mask;
      rcaLval5 = ( rcaNode5 >> 32 ) & mask;

      rcaRval6 = rcaNode6 & mask;
      rcaLval6 = ( rcaNode6 >> 32 ) & mask;

      rcaRval7 = rcaNode7 & mask;
      rcaLval7 = ( rcaNode7 >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;

         nnzRval1 = nnzNode1 & mask;
         nnzLval1 = ( nnzNode1 >> 32 ) & mask;

         nnzRval2 = nnzNode2 & mask;
         nnzLval2 = ( nnzNode2 >> 32 ) & mask;

         nnzRval3 = nnzNode3 & mask;
         nnzLval3 = ( nnzNode3 >> 32 ) & mask;

         nnzRval4 = nnzNode4 & mask;
         nnzLval4 = ( nnzNode4 >> 32 ) & mask;

         nnzRval5 = nnzNode5 & mask;
         nnzLval5 = ( nnzNode5 >> 32 ) & mask;

         nnzRval6 = nnzNode6 & mask;
         nnzLval6 = ( nnzNode6 >> 32 ) & mask;

         nnzRval7 = nnzNode7 & mask;
         nnzLval7 = ( nnzNode7 >> 32 ) & mask;
      
         lvl--;
         // DEBUG_PRINT( "Found nnzRval0" );
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzRval0;
         prcaStack0[sp] = rcaRval0;
         pnnzStack1[sp] = nnzRval1;
         prcaStack1[sp] = rcaRval1;
         pnnzStack2[sp] = nnzRval2;
         prcaStack2[sp] = rcaRval2;
         pnnzStack3[sp] = nnzRval3;
         prcaStack3[sp] = rcaRval3;
         pnnzStack4[sp] = nnzRval4;
         prcaStack4[sp] = rcaRval4;
         pnnzStack5[sp] = nnzRval5;
         prcaStack5[sp] = rcaRval5;
         pnnzStack6[sp] = nnzRval6;
         prcaStack6[sp] = rcaRval6;
         pnnzStack7[sp] = nnzRval7;
         prcaStack7[sp] = rcaRval7;
         sp++;
         
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzLval0;
         prcaStack0[sp] = rcaLval0;
         pnnzStack1[sp] = nnzLval1;
         prcaStack1[sp] = rcaLval1;
         pnnzStack2[sp] = nnzLval2;
         prcaStack2[sp] = rcaLval2;
         pnnzStack3[sp] = nnzLval3;
         prcaStack3[sp] = rcaLval3;
         pnnzStack4[sp] = nnzLval4;
         prcaStack4[sp] = rcaLval4;
         pnnzStack5[sp] = nnzLval5;
         prcaStack5[sp] = rcaLval5;
         pnnzStack6[sp] = nnzLval6;
         prcaStack6[sp] = rcaLval6;
         pnnzStack7[sp] = nnzLval7;
         prcaStack7[sp] = rcaLval7;
         sp++;
      }
      else {
         // leaf node
         DEBUG_PRINT( "Leaf node" );
         USD64 v0;
         USD64 v1;
         USD64 v2;
         USD64 v3;
         USD64 v4;
         USD64 v5;
         USD64 v6;
         USD64 v7;
         v0.u = nnzNode0;
         v1.u = nnzNode1;
         v2.u = nnzNode2;
         v3.u = nnzNode3;
         v4.u = nnzNode4;
         v5.u = nnzNode5;
         v6.u = nnzNode6;
         v7.u = nnzNode7;
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         r1 += rcaLval1 + 1;
         c1 += rcaRval1 + 1;
         r2 += rcaLval2 + 1;
         c2 += rcaRval2 + 1;
         r3 += rcaLval3 + 1;
         c3 += rcaRval3 + 1;
         r4 += rcaLval4 + 1;
         c4 += rcaRval4 + 1;
         r5 += rcaLval5 + 1;
         c5 += rcaRval5 + 1;
         r6 += rcaLval6 + 1;
         c6 += rcaRval6 + 1;
         r7 += rcaLval7 + 1;
         c7 += rcaRval7 + 1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "r1 = " << r1 << ", c1 = " << c1 );
         DEBUG_PRINT( "r2 = " << r2 << ", c2 = " << c2 );
         DEBUG_PRINT( "r3 = " << r3 << ", c3 = " << c3 );
         DEBUG_PRINT( "r4 = " << r4 << ", c4 = " << c4 );
         DEBUG_PRINT( "r5 = " << r5 << ", c5 = " << c5 );
         DEBUG_PRINT( "r6 = " << r6 << ", c6 = " << c6 );
         DEBUG_PRINT( "r7 = " << r7 << ", c7 = " << c7 );
         DEBUG_PRINT( "" );
         _y[r0] += v0.d * _x[c0];
         _y[r1] += v1.d * _x[c1];
         _y[r2] += v2.d * _x[c2];
         _y[r3] += v3.d * _x[c3];
         _y[r4] += v4.d * _x[c4];
         _y[r5] += v5.d * _x[c5];
         _y[r6] += v6.d * _x[c6];
         _y[r7] += v7.d * _x[c7];
      }
   }
   
   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving SpMVFlatKernelCOO_HL8() " );
}
void SpMVFlatKernelCOO_HL16( const U32 _hgt, const U64 * _nodes, const U32 _nnzIdx0, const U32 _rcaIdx0, 
                                                                 const U32 _nnzIdx1, const U32 _rcaIdx1,
                                                                 const U32 _nnzIdx2, const U32 _rcaIdx2,
                                                                 const U32 _nnzIdx3, const U32 _rcaIdx3,
                                                                 const U32 _nnzIdx4, const U32 _rcaIdx4,
                                                                 const U32 _nnzIdx5, const U32 _rcaIdx5,
                                                                 const U32 _nnzIdx6, const U32 _rcaIdx6,
                                                                 const U32 _nnzIdx7, const U32 _rcaIdx7,
                                                                 const U32 _nnzIdx8, const U32 _rcaIdx8,
                                                                 const U32 _nnzIdx9, const U32 _rcaIdx9,
                                                                 const U32 _nnzIdxA, const U32 _rcaIdxA,
                                                                 const U32 _nnzIdxB, const U32 _rcaIdxB,
                                                                 const U32 _nnzIdxC, const U32 _rcaIdxC,
                                                                 const U32 _nnzIdxD, const U32 _rcaIdxD,
                                                                 const U32 _nnzIdxE, const U32 _rcaIdxE,
                                                                 const U32 _nnzIdxF, const U32 _rcaIdxF,
                                                                 const double * _x, double * _y, timespec * clks )
{
   DEBUG_PRINT( "entering SpMVFlatKernelCOO_HL16() " );
   DEBUG_PRINT( "_hgt = " << _hgt );
   
   const U64 numAlloc = 40;

   U32 lvlStack[ numAlloc ];
   
   U32 pnnzStack0[ numAlloc ];
   U32 pnnzStack1[ numAlloc ];
   U32 pnnzStack2[ numAlloc ];
   U32 pnnzStack3[ numAlloc ];
   U32 pnnzStack4[ numAlloc ];
   U32 pnnzStack5[ numAlloc ];
   U32 pnnzStack6[ numAlloc ];
   U32 pnnzStack7[ numAlloc ];
   U32 pnnzStack8[ numAlloc ];
   U32 pnnzStack9[ numAlloc ];
   U32 pnnzStackA[ numAlloc ];
   U32 pnnzStackB[ numAlloc ];
   U32 pnnzStackC[ numAlloc ];
   U32 pnnzStackD[ numAlloc ];
   U32 pnnzStackE[ numAlloc ];
   U32 pnnzStackF[ numAlloc ];

   U32 prcaStack0[ numAlloc ];
   U32 prcaStack1[ numAlloc ];
   U32 prcaStack2[ numAlloc ];
   U32 prcaStack3[ numAlloc ];
   U32 prcaStack4[ numAlloc ];
   U32 prcaStack5[ numAlloc ];
   U32 prcaStack6[ numAlloc ];
   U32 prcaStack7[ numAlloc ];
   U32 prcaStack8[ numAlloc ];
   U32 prcaStack9[ numAlloc ];
   U32 prcaStackA[ numAlloc ];
   U32 prcaStackB[ numAlloc ];
   U32 prcaStackC[ numAlloc ];
   U32 prcaStackD[ numAlloc ];
   U32 prcaStackE[ numAlloc ];
   U32 prcaStackF[ numAlloc ];

   const U32 mask = 0xFFFFFFFF;

   U32 r0 = 0;
   U32 r1 = 0;
   U32 r2 = 0;
   U32 r3 = 0;
   U32 r4 = 0;
   U32 r5 = 0;
   U32 r6 = 0;
   U32 r7 = 0;
   U32 r8 = 0;
   U32 r9 = 0;
   U32 rA = 0;
   U32 rB = 0;
   U32 rC = 0;
   U32 rD = 0;
   U32 rE = 0;
   U32 rF = 0;
      
   U32 c0 = 0;
   U32 c1 = 0;
   U32 c2 = 0;
   U32 c3 = 0;
   U32 c4 = 0;
   U32 c5 = 0;
   U32 c6 = 0;
   U32 c7 = 0;
   U32 c8 = 0;
   U32 c9 = 0;
   U32 cA = 0;
   U32 cB = 0;
   U32 cC = 0;
   U32 cD = 0;
   U32 cE = 0;
   U32 cF = 0;
   
   U32 nnzLval0;
   U32 nnzRval0;
   U32 nnzLval1;
   U32 nnzRval1;
   U32 nnzLval2;
   U32 nnzRval2;
   U32 nnzLval3;
   U32 nnzRval3;
   U32 nnzLval4;
   U32 nnzRval4;
   U32 nnzLval5;
   U32 nnzRval5;
   U32 nnzLval6;
   U32 nnzRval6;
   U32 nnzLval7;
   U32 nnzRval7;
   U32 nnzLval8;
   U32 nnzRval8;
   U32 nnzLval9;
   U32 nnzRval9;
   U32 nnzLvalA;
   U32 nnzRvalA;
   U32 nnzLvalB;
   U32 nnzRvalB;
   U32 nnzLvalC;
   U32 nnzRvalC;
   U32 nnzLvalD;
   U32 nnzRvalD;
   U32 nnzLvalE;
   U32 nnzRvalE;
   U32 nnzLvalF;
   U32 nnzRvalF;
   
   S32 rcaLval0;
   S32 rcaRval0;
   S32 rcaLval1;
   S32 rcaRval1;
   S32 rcaLval2;
   S32 rcaRval2;
   S32 rcaLval3;
   S32 rcaRval3;
   S32 rcaLval4;
   S32 rcaRval4;
   S32 rcaLval5;
   S32 rcaRval5;
   S32 rcaLval6;
   S32 rcaRval6;
   S32 rcaLval7;
   S32 rcaRval7;
   S32 rcaLval8;
   S32 rcaRval8;
   S32 rcaLval9;
   S32 rcaRval9;
   S32 rcaLvalA;
   S32 rcaRvalA;
   S32 rcaLvalB;
   S32 rcaRvalB;
   S32 rcaLvalC;
   S32 rcaRvalC;
   S32 rcaLvalD;
   S32 rcaRvalD;
   S32 rcaLvalE;
   S32 rcaRvalE;
   S32 rcaLvalF;
   S32 rcaRvalF;
   
   U32 sp = 1;
   U32 lvl = _hgt;
      
   U64 nnzNode0;
   U64 rcaNode0;
   U64 nnzNode1;
   U64 rcaNode1;
   U64 nnzNode2;
   U64 rcaNode2;
   U64 nnzNode3;
   U64 rcaNode3;
   U64 nnzNode4;
   U64 rcaNode4;
   U64 nnzNode5;
   U64 rcaNode5;
   U64 nnzNode6;
   U64 rcaNode6;
   U64 nnzNode7;
   U64 rcaNode7;
   U64 nnzNode8;
   U64 rcaNode8;
   U64 nnzNode9;
   U64 rcaNode9;
   U64 nnzNodeA;
   U64 rcaNodeA;
   U64 nnzNodeB;
   U64 rcaNodeB;
   U64 nnzNodeC;
   U64 rcaNodeC;
   U64 nnzNodeD;
   U64 rcaNodeD;
   U64 nnzNodeE;
   U64 rcaNodeE;
   U64 nnzNodeF;
   U64 rcaNodeF;
   
   // must init ptr stack to zero
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      lvlStack[ ii ] = _hgt;
      pnnzStack0[ ii ] = 0;
      prcaStack0[ ii ] = 0;
      pnnzStack1[ ii ] = 0;
      prcaStack1[ ii ] = 0;
      pnnzStack2[ ii ] = 0;
      prcaStack2[ ii ] = 0;
      pnnzStack3[ ii ] = 0;
      prcaStack3[ ii ] = 0;
      pnnzStack4[ ii ] = 0;
      prcaStack4[ ii ] = 0;
      pnnzStack5[ ii ] = 0;
      prcaStack5[ ii ] = 0;
      pnnzStack6[ ii ] = 0;
      prcaStack6[ ii ] = 0;
      pnnzStack7[ ii ] = 0;
      prcaStack7[ ii ] = 0;
      pnnzStack8[ ii ] = 0;
      prcaStack8[ ii ] = 0;
      pnnzStack9[ ii ] = 0;
      prcaStack9[ ii ] = 0;
      pnnzStackA[ ii ] = 0;
      prcaStackA[ ii ] = 0;
      pnnzStackB[ ii ] = 0;
      prcaStackB[ ii ] = 0;
      pnnzStackC[ ii ] = 0;
      prcaStackC[ ii ] = 0;
      pnnzStackD[ ii ] = 0;
      prcaStackD[ ii ] = 0;
      pnnzStackE[ ii ] = 0;
      prcaStackE[ ii ] = 0;
      pnnzStackF[ ii ] = 0;
      prcaStackF[ ii ] = 0;
   }

   pnnzStack0[ 0 ] = _nnzIdx0;
   prcaStack0[ 0 ] = _rcaIdx0;
   pnnzStack1[ 0 ] = _nnzIdx1;
   prcaStack1[ 0 ] = _rcaIdx1;
   pnnzStack2[ 0 ] = _nnzIdx2;
   prcaStack2[ 0 ] = _rcaIdx2;
   pnnzStack3[ 0 ] = _nnzIdx3;
   prcaStack3[ 0 ] = _rcaIdx3;
   pnnzStack4[ 0 ] = _nnzIdx4;
   prcaStack4[ 0 ] = _rcaIdx4;
   pnnzStack5[ 0 ] = _nnzIdx5;
   prcaStack5[ 0 ] = _rcaIdx5;
   pnnzStack6[ 0 ] = _nnzIdx6;
   prcaStack6[ 0 ] = _rcaIdx6;
   pnnzStack7[ 0 ] = _nnzIdx7;
   prcaStack7[ 0 ] = _rcaIdx7;
   pnnzStack8[ 0 ] = _nnzIdx8;
   prcaStack8[ 0 ] = _rcaIdx8;
   pnnzStack9[ 0 ] = _nnzIdx9;
   prcaStack9[ 0 ] = _rcaIdx9;
   pnnzStackA[ 0 ] = _nnzIdxA;
   prcaStackA[ 0 ] = _rcaIdxA;
   pnnzStackB[ 0 ] = _nnzIdxB;
   prcaStackB[ 0 ] = _rcaIdxB;
   pnnzStackC[ 0 ] = _nnzIdxC;
   prcaStackC[ 0 ] = _rcaIdxC;
   pnnzStackD[ 0 ] = _nnzIdxD;
   prcaStackD[ 0 ] = _rcaIdxD;
   pnnzStackE[ 0 ] = _nnzIdxE;
   prcaStackE[ 0 ] = _rcaIdxE;
   pnnzStackF[ 0 ] = _nnzIdxF;
   prcaStackF[ 0 ] = _rcaIdxF;

   clock_gettime( CLOCK_MONOTONIC, clks   );

   while( sp ) {
      
      sp--;

      lvl = lvlStack[ sp ];
      nnzNode0 = _nodes[ pnnzStack0[sp] ];
      rcaNode0 = _nodes[ prcaStack0[sp] ];
      nnzNode1 = _nodes[ pnnzStack1[sp] ];
      rcaNode1 = _nodes[ prcaStack1[sp] ];
      nnzNode2 = _nodes[ pnnzStack2[sp] ];
      rcaNode2 = _nodes[ prcaStack2[sp] ];
      nnzNode3 = _nodes[ pnnzStack3[sp] ];
      rcaNode3 = _nodes[ prcaStack3[sp] ];
      nnzNode4 = _nodes[ pnnzStack4[sp] ];
      rcaNode4 = _nodes[ prcaStack4[sp] ];
      nnzNode5 = _nodes[ pnnzStack5[sp] ];
      rcaNode5 = _nodes[ prcaStack5[sp] ];
      nnzNode6 = _nodes[ pnnzStack6[sp] ];
      rcaNode6 = _nodes[ prcaStack6[sp] ];
      nnzNode7 = _nodes[ pnnzStack7[sp] ];
      rcaNode7 = _nodes[ prcaStack7[sp] ];
      nnzNode8 = _nodes[ pnnzStack8[sp] ];
      rcaNode8 = _nodes[ prcaStack8[sp] ];
      nnzNode9 = _nodes[ pnnzStack9[sp] ];
      rcaNode9 = _nodes[ prcaStack9[sp] ];
      nnzNodeA = _nodes[ pnnzStackA[sp] ];
      rcaNodeA = _nodes[ prcaStackA[sp] ];
      nnzNodeB = _nodes[ pnnzStackB[sp] ];
      rcaNodeB = _nodes[ prcaStackB[sp] ];
      nnzNodeC = _nodes[ pnnzStackC[sp] ];
      rcaNodeC = _nodes[ prcaStackC[sp] ];
      nnzNodeD = _nodes[ pnnzStackD[sp] ];
      rcaNodeD = _nodes[ prcaStackD[sp] ];
      nnzNodeE = _nodes[ pnnzStackE[sp] ];
      rcaNodeE = _nodes[ prcaStackE[sp] ];
      nnzNodeF = _nodes[ pnnzStackF[sp] ];
      rcaNodeF = _nodes[ prcaStackF[sp] ];
      
      // DEBUG_PRINT( "Decoding rca node." );
      rcaRval0 = rcaNode0 & mask;
      rcaLval0 = ( rcaNode0 >> 32 ) & mask;

      rcaRval1 = rcaNode1 & mask;
      rcaLval1 = ( rcaNode1 >> 32 ) & mask;

      rcaRval2 = rcaNode2 & mask;
      rcaLval2 = ( rcaNode2 >> 32 ) & mask;

      rcaRval3 = rcaNode3 & mask;
      rcaLval3 = ( rcaNode3 >> 32 ) & mask;

      rcaRval4 = rcaNode4 & mask;
      rcaLval4 = ( rcaNode4 >> 32 ) & mask;

      rcaRval5 = rcaNode5 & mask;
      rcaLval5 = ( rcaNode5 >> 32 ) & mask;

      rcaRval6 = rcaNode6 & mask;
      rcaLval6 = ( rcaNode6 >> 32 ) & mask;

      rcaRval7 = rcaNode7 & mask;
      rcaLval7 = ( rcaNode7 >> 32 ) & mask;

      rcaRval8 = rcaNode8 & mask;
      rcaLval8 = ( rcaNode8 >> 32 ) & mask;

      rcaRval9 = rcaNode9 & mask;
      rcaLval9 = ( rcaNode9 >> 32 ) & mask;

      rcaRvalA = rcaNodeA & mask;
      rcaLvalA = ( rcaNodeA >> 32 ) & mask;

      rcaRvalB = rcaNodeB & mask;
      rcaLvalB = ( rcaNodeB >> 32 ) & mask;

      rcaRvalC = rcaNodeC & mask;
      rcaLvalC = ( rcaNodeC >> 32 ) & mask;

      rcaRvalD = rcaNodeD & mask;
      rcaLvalD = ( rcaNodeD >> 32 ) & mask;

      rcaRvalE = rcaNodeE & mask;
      rcaLvalE = ( rcaNodeE >> 32 ) & mask;

      rcaRvalF = rcaNodeF & mask;
      rcaLvalF = ( rcaNodeF >> 32 ) & mask;
      
      if( lvl ) {
         // internal node
         // DEBUG_PRINT( "Decoding nnz node." );
         nnzRval0 = nnzNode0 & mask;
         nnzLval0 = ( nnzNode0 >> 32 ) & mask;

         nnzRval1 = nnzNode1 & mask;
         nnzLval1 = ( nnzNode1 >> 32 ) & mask;

         nnzRval2 = nnzNode2 & mask;
         nnzLval2 = ( nnzNode2 >> 32 ) & mask;

         nnzRval3 = nnzNode3 & mask;
         nnzLval3 = ( nnzNode3 >> 32 ) & mask;

         nnzRval4 = nnzNode4 & mask;
         nnzLval4 = ( nnzNode4 >> 32 ) & mask;

         nnzRval5 = nnzNode5 & mask;
         nnzLval5 = ( nnzNode5 >> 32 ) & mask;

         nnzRval6 = nnzNode6 & mask;
         nnzLval6 = ( nnzNode6 >> 32 ) & mask;

         nnzRval7 = nnzNode7 & mask;
         nnzLval7 = ( nnzNode7 >> 32 ) & mask;

         nnzRval8 = nnzNode8 & mask;
         nnzLval8 = ( nnzNode8 >> 32 ) & mask;

         nnzRval9 = nnzNode9 & mask;
         nnzLval9 = ( nnzNode9 >> 32 ) & mask;

         nnzRvalA = nnzNodeA & mask;
         nnzLvalA = ( nnzNodeA >> 32 ) & mask;

         nnzRvalB = nnzNodeB & mask;
         nnzLvalB = ( nnzNodeB >> 32 ) & mask;

         nnzRvalC = nnzNodeC & mask;
         nnzLvalC = ( nnzNodeC >> 32 ) & mask;

         nnzRvalD = nnzNodeD & mask;
         nnzLvalD = ( nnzNodeD >> 32 ) & mask;

         nnzRvalE = nnzNodeE & mask;
         nnzLvalE = ( nnzNodeE >> 32 ) & mask;

         nnzRvalF = nnzNodeF & mask;
         nnzLvalF = ( nnzNodeF >> 32 ) & mask;
      
         lvl--;
         // DEBUG_PRINT( "Found nnzRval0" );
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzRval0;
         prcaStack0[sp] = rcaRval0;
         pnnzStack1[sp] = nnzRval1;
         prcaStack1[sp] = rcaRval1;
         pnnzStack2[sp] = nnzRval2;
         prcaStack2[sp] = rcaRval2;
         pnnzStack3[sp] = nnzRval3;
         prcaStack3[sp] = rcaRval3;
         pnnzStack4[sp] = nnzRval4;
         prcaStack4[sp] = rcaRval4;
         pnnzStack5[sp] = nnzRval5;
         prcaStack5[sp] = rcaRval5;
         pnnzStack6[sp] = nnzRval6;
         prcaStack6[sp] = rcaRval6;
         pnnzStack7[sp] = nnzRval7;
         prcaStack7[sp] = rcaRval7;
         pnnzStack8[sp] = nnzRval8;
         prcaStack8[sp] = rcaRval8;
         pnnzStack9[sp] = nnzRval9;
         prcaStack9[sp] = rcaRval9;
         pnnzStackA[sp] = nnzRvalA;
         prcaStackA[sp] = rcaRvalA;
         pnnzStackB[sp] = nnzRvalB;
         prcaStackB[sp] = rcaRvalB;
         pnnzStackC[sp] = nnzRvalC;
         prcaStackC[sp] = rcaRvalC;
         pnnzStackD[sp] = nnzRvalD;
         prcaStackD[sp] = rcaRvalD;
         pnnzStackE[sp] = nnzRvalE;
         prcaStackE[sp] = rcaRvalE;
         pnnzStackF[sp] = nnzRvalF;
         prcaStackF[sp] = rcaRvalF;
         sp++;
         
         lvlStack[sp] = lvl;
         pnnzStack0[sp] = nnzLval0;
         prcaStack0[sp] = rcaLval0;
         pnnzStack1[sp] = nnzLval1;
         prcaStack1[sp] = rcaLval1;
         pnnzStack2[sp] = nnzLval2;
         prcaStack2[sp] = rcaLval2;
         pnnzStack3[sp] = nnzLval3;
         prcaStack3[sp] = rcaLval3;
         pnnzStack4[sp] = nnzLval4;
         prcaStack4[sp] = rcaLval4;
         pnnzStack5[sp] = nnzLval5;
         prcaStack5[sp] = rcaLval5;
         pnnzStack6[sp] = nnzLval6;
         prcaStack6[sp] = rcaLval6;
         pnnzStack7[sp] = nnzLval7;
         prcaStack7[sp] = rcaLval7;
         pnnzStack8[sp] = nnzLval8;
         prcaStack8[sp] = rcaLval8;
         pnnzStack9[sp] = nnzLval9;
         prcaStack9[sp] = rcaLval9;
         pnnzStackA[sp] = nnzLvalA;
         prcaStackA[sp] = rcaLvalA;
         pnnzStackB[sp] = nnzLvalB;
         prcaStackB[sp] = rcaLvalB;
         pnnzStackC[sp] = nnzLvalC;
         prcaStackC[sp] = rcaLvalC;
         pnnzStackD[sp] = nnzLvalD;
         prcaStackD[sp] = rcaLvalD;
         pnnzStackE[sp] = nnzLvalE;
         prcaStackE[sp] = rcaLvalE;
         pnnzStackF[sp] = nnzLvalF;
         prcaStackF[sp] = rcaLvalF;
         sp++;
      }
      else {
         // leaf node
         DEBUG_PRINT( "Leaf node" );
         USD64 v0;
         USD64 v1;
         USD64 v2;
         USD64 v3;
         USD64 v4;
         USD64 v5;
         USD64 v6;
         USD64 v7;
         USD64 v8;
         USD64 v9;
         USD64 vA;
         USD64 vB;
         USD64 vC;
         USD64 vD;
         USD64 vE;
         USD64 vF;
         v0.u = nnzNode0;
         v1.u = nnzNode1;
         v2.u = nnzNode2;
         v3.u = nnzNode3;
         v4.u = nnzNode4;
         v5.u = nnzNode5;
         v6.u = nnzNode6;
         v7.u = nnzNode7;
         v8.u = nnzNode8;
         v9.u = nnzNode9;
         vA.u = nnzNodeA;
         vB.u = nnzNodeB;
         vC.u = nnzNodeC;
         vD.u = nnzNodeD;
         vE.u = nnzNodeE;
         vF.u = nnzNodeF;
         r0 += rcaLval0 + 1;
         c0 += rcaRval0 + 1;
         r1 += rcaLval1 + 1;
         c1 += rcaRval1 + 1;
         r2 += rcaLval2 + 1;
         c2 += rcaRval2 + 1;
         r3 += rcaLval3 + 1;
         c3 += rcaRval3 + 1;
         r4 += rcaLval4 + 1;
         c4 += rcaRval4 + 1;
         r5 += rcaLval5 + 1;
         c5 += rcaRval5 + 1;
         r6 += rcaLval6 + 1;
         c6 += rcaRval6 + 1;
         r7 += rcaLval7 + 1;
         c7 += rcaRval7 + 1;
         r8 += rcaLval8 + 1;
         c8 += rcaRval8 + 1;
         r9 += rcaLval9 + 1;
         c9 += rcaRval9 + 1;
         rA += rcaLvalA + 1;
         cA += rcaRvalA + 1;
         rB += rcaLvalB + 1;
         cB += rcaRvalB + 1;
         rC += rcaLvalC + 1;
         cC += rcaRvalC + 1;
         rD += rcaLvalD + 1;
         cD += rcaRvalD + 1;
         rE += rcaLvalE + 1;
         cE += rcaRvalE + 1;
         rF += rcaLvalF + 1;
         cF += rcaRvalF + 1;
         DEBUG_PRINT( "r0 = " << r0 << ", c0 = " << c0 );
         DEBUG_PRINT( "r1 = " << r1 << ", c1 = " << c1 );
         DEBUG_PRINT( "r2 = " << r2 << ", c2 = " << c2 );
         DEBUG_PRINT( "r3 = " << r3 << ", c3 = " << c3 );
         DEBUG_PRINT( "r4 = " << r4 << ", c4 = " << c4 );
         DEBUG_PRINT( "r5 = " << r5 << ", c5 = " << c5 );
         DEBUG_PRINT( "r6 = " << r6 << ", c6 = " << c6 );
         DEBUG_PRINT( "r7 = " << r7 << ", c7 = " << c7 );
         DEBUG_PRINT( "" );
         _y[r0] += v0.d * _x[c0];
         _y[r1] += v1.d * _x[c1];
         _y[r2] += v2.d * _x[c2];
         _y[r3] += v3.d * _x[c3];
         _y[r4] += v4.d * _x[c4];
         _y[r5] += v5.d * _x[c5];
         _y[r6] += v6.d * _x[c6];
         _y[r7] += v7.d * _x[c7];
         _y[r8] += v8.d * _x[c8];
         _y[r9] += v9.d * _x[c9];
         _y[rA] += vA.d * _x[cA];
         _y[rB] += vB.d * _x[cB];
         _y[rC] += vC.d * _x[cC];
         _y[rD] += vD.d * _x[cD];
         _y[rE] += vE.d * _x[cE];
         _y[rF] += vF.d * _x[cF];
      }
   }
   
   clock_gettime( CLOCK_MONOTONIC, clks+1 );

   DEBUG_PRINT( "leaving SpMVFlatKernelCOO_HL16() " );
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SpMVFlatKernelCSR( const U64 _nnz, const U64 _m, const U32 _nnzHgt, const U32 _idxHgt, const U32 _ptrHgt, const U64 * _nodes,
                        const U32 _nnzValsRootNodePtr,
                        const U32 _colIdxsRootNodePtr,
                        const U32 _rowPtrsRootNodePtr,
                        const double * x, double * y, timespec * clks )
{
   DEBUG_PRINT( "entering SpMVFlatKernelCSR() " );
   y--;
   
   S32 nnzCount = 0;
   S32 rowCount = -1;
   const U64 numAlloc = 40;
   const S32 m = _m;
   const S32 nnz = _nnz;

   U32 idxLvlStack[ numAlloc ];
   U32 ptrLvlStack[ numAlloc ];
   U32 nnzLvlStack[ numAlloc ];
   U32 nnzPtrStack[ numAlloc ];
   U32 idxPtrStack[ numAlloc ];
   U32 ptrPtrStack[ numAlloc ];
   
   U32 nnzPtr = _nnzValsRootNodePtr << 2;
   U32 idxPtr = _colIdxsRootNodePtr << 2;
   U32 ptrPtr = _rowPtrsRootNodePtr << 2;
   
   S32    rowBrks[4] = {   0,   0,   0,   0 };
   S32    colIdxs[4] = {   0,   0,   0,   0 };
   double nnzVals[4] = { 0.0, 0.0, 0.0, 0.0 };
   double   xVals[4] = { 0.0, 0.0, 0.0, 0.0 };
   
   const    S32 *   nodes = (const S32    *) _nodes;
   const double * d_nodes = (const double *) _nodes;
   
   U32 nnzPtr0 = nodes[ nnzPtr + 1 ];
   U32 nnzPtr1 = nodes[ nnzPtr + 0 ];
   U32 nnzPtr2 = nodes[ nnzPtr + 3 ];
   U32 nnzPtr3 = nodes[ nnzPtr + 2 ];

   U32 idxPtr0 = nodes[ idxPtr + 1 ];
   U32 idxPtr1 = nodes[ idxPtr + 0 ];
   U32 idxPtr2 = nodes[ idxPtr + 3 ];
   U32 idxPtr3 = nodes[ idxPtr + 2 ];

   U32 ptrPtr0 = nodes[ ptrPtr + 1 ];
   U32 ptrPtr1 = nodes[ ptrPtr + 0 ];
   U32 ptrPtr2 = nodes[ ptrPtr + 3 ];
   U32 ptrPtr3 = nodes[ ptrPtr + 2 ];
   
   if( false ) {
      printf( "nnzPtr0 = %d\n", nnzPtr0 );
      printf( "nnzPtr1 = %d\n", nnzPtr1 );
      printf( "nnzPtr2 = %d\n", nnzPtr2 );
      printf( "nnzPtr3 = %d\n", nnzPtr3 );
      printf( "idxPtr0 = %d\n", idxPtr0 );
      printf( "idxPtr1 = %d\n", idxPtr1 );
      printf( "idxPtr2 = %d\n", idxPtr2 );
      printf( "idxPtr3 = %d\n", idxPtr3 );
      printf( "ptrPtr0 = %d\n", ptrPtr0 );
      printf( "ptrPtr1 = %d\n", ptrPtr1 );
      printf( "ptrPtr2 = %d\n", ptrPtr2 );
      printf( "ptrPtr3 = %d\n", ptrPtr3 );
   }
   
   U32 idx_sp = 0;
   U32 ptr_sp = 0;
   
   U32 idxLvl = _idxHgt;
   U32 ptrLvl = _ptrHgt;
   U32 nnzLvl = _nnzHgt;
      
   // must init ptr stack to zero
   DEBUG_PRINT( "initializing stacks" );
   for( U32 ii = 0; ii < numAlloc; ii++ ) {
      nnzLvlStack[ ii ] = _nnzHgt;
      idxLvlStack[ ii ] = _idxHgt;
      ptrLvlStack[ ii ] = _ptrHgt;
      nnzPtrStack[ ii ] = 0;
      idxPtrStack[ ii ] = 0;
      ptrPtrStack[ ii ] = 0;
   }
   nnzPtrStack[ idx_sp ] = nnzPtr3;
   idxPtrStack[ idx_sp ] = idxPtr3;
   idx_sp++;

   nnzPtrStack[ idx_sp ] = nnzPtr2;
   idxPtrStack[ idx_sp ] = idxPtr2;
   idx_sp++;

   nnzPtrStack[ idx_sp ] = nnzPtr1;
   idxPtrStack[ idx_sp ] = idxPtr1;
   idx_sp++;

   nnzPtrStack[ idx_sp ] = nnzPtr0;
   idxPtrStack[ idx_sp ] = idxPtr0;
   idx_sp++;
   
   ptrPtrStack[ ptr_sp ] = ptrPtr3; ptr_sp++;
   ptrPtrStack[ ptr_sp ] = ptrPtr2; ptr_sp++;
   ptrPtrStack[ ptr_sp ] = ptrPtr1; ptr_sp++;
   ptrPtrStack[ ptr_sp ] = ptrPtr0; ptr_sp++;

   clock_gettime( CLOCK_MONOTONIC, clks   );
   
   U32 nnz_sp = idx_sp;

   while( nnzLvl > idxLvl ) {
      nnz_sp--;
      nnzLvl--;
      
      nnzPtr = nnzPtrStack[ nnz_sp ] << 2;

      nnzPtr0 = nodes[ nnzPtr + 1 ];
      nnzPtr1 = nodes[ nnzPtr + 0 ];
      nnzPtr2 = nodes[ nnzPtr + 3 ];
      nnzPtr3 = nodes[ nnzPtr + 2 ];
      
      nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr3; nnz_sp++;
      nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr2; nnz_sp++;
      nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr1; nnz_sp++;
      nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr0; nnz_sp++;
   }

   while( nnzCount < nnz ) {
      ptr_sp--;
      ptrLvl = ptrLvlStack[ ptr_sp ];

      while( ptrLvl ) {
         
         ptrPtr = ptrPtrStack[ ptr_sp ] << 2;
         ptrLvl = ptrLvlStack[ ptr_sp ];
      
         ptrPtr0 = nodes[ ptrPtr + 1 ];
         ptrPtr1 = nodes[ ptrPtr + 0 ];
         ptrPtr2 = nodes[ ptrPtr + 3 ];
         ptrPtr3 = nodes[ ptrPtr + 2 ];
         
         ptrLvl--;
         ptrLvlStack[ ptr_sp ] = ptrLvl; ptrPtrStack[ ptr_sp ] = ptrPtr3; ptr_sp++;
         ptrLvlStack[ ptr_sp ] = ptrLvl; ptrPtrStack[ ptr_sp ] = ptrPtr2; ptr_sp++;
         ptrLvlStack[ ptr_sp ] = ptrLvl; ptrPtrStack[ ptr_sp ] = ptrPtr1; ptr_sp++;
         ptrLvlStack[ ptr_sp ] = ptrLvl; ptrPtrStack[ ptr_sp ] = ptrPtr0; ptr_sp++;
         ptr_sp--;
      }
      
      ptrPtr = ptrPtrStack[ ptr_sp ] << 2;

      rowBrks[0] = ((S32)nodes[ ptrPtr + 1 ]) + 1 + rowBrks[3];
      rowBrks[1] = ((S32)nodes[ ptrPtr + 0 ]) + 1 + rowBrks[0];
      rowBrks[2] = ((S32)nodes[ ptrPtr + 3 ]) + 1 + rowBrks[1];
      rowBrks[3] = ((S32)nodes[ ptrPtr + 2 ]) + 1 + rowBrks[2];

      U32 rowBrkIdx = 0;
      while( rowBrkIdx < 4 && rowCount < m ) {
         
         while( nnzCount < rowBrks[ rowBrkIdx ] && nnzCount < nnz ) {
            
            idx_sp--;
            nnz_sp--;
            idxLvl = idxLvlStack[ idx_sp ];
            nnzLvl = nnzLvlStack[ nnz_sp ];
            
            if( idxLvl && nnzLvl ) {
               // internal node
               idxPtr = idxPtrStack[ idx_sp ] << 2;
               nnzPtr = nnzPtrStack[ nnz_sp ] << 2;
               
               const S32 * idxNodes = &nodes[ idxPtr ];
               idxPtr1 = *idxNodes; idxNodes++;
               idxPtr0 = *idxNodes; idxNodes++;
               idxPtr3 = *idxNodes; idxNodes++;
               idxPtr2 = *idxNodes;
               
               const S32 * nnzNodes = &nodes[ nnzPtr ];
               nnzPtr1 = *nnzNodes; nnzNodes++;
               nnzPtr0 = *nnzNodes; nnzNodes++;
               nnzPtr3 = *nnzNodes; nnzNodes++;
               nnzPtr2 = *nnzNodes;            
      
               idxLvl--;
               nnzLvl--;
      
               idxLvlStack[ idx_sp ] = idxLvl; idxPtrStack[ idx_sp ] = idxPtr3; idx_sp++;
               idxLvlStack[ idx_sp ] = idxLvl; idxPtrStack[ idx_sp ] = idxPtr2; idx_sp++;
               idxLvlStack[ idx_sp ] = idxLvl; idxPtrStack[ idx_sp ] = idxPtr1; idx_sp++;
               idxLvlStack[ idx_sp ] = idxLvl; idxPtrStack[ idx_sp ] = idxPtr0; idx_sp++;
      
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr3; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr2; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr1; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr0; nnz_sp++;
            }
            else if( nnzLvl ) {
      
               idx_sp++;
               // internal node
               nnzPtr = nnzPtrStack[ nnz_sp ] << 2;
               
               const S32 * nnzNodes = &nodes[ nnzPtr ];
               nnzPtr1 = *nnzNodes; nnzNodes++;
               nnzPtr0 = *nnzNodes; nnzNodes++;
               nnzPtr3 = *nnzNodes; nnzNodes++;
               nnzPtr2 = *nnzNodes;
      
               nnzLvl--;
      
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr3; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr2; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr1; nnz_sp++;
               nnzLvlStack[ nnz_sp ] = nnzLvl; nnzPtrStack[ nnz_sp ] = nnzPtr0; nnz_sp++;            
            }
            else {
               nnzCount += 4;
               // leaf node
      
               idxPtr = idxPtrStack[ idx_sp ] << 2;
               nnzPtr = nnzPtrStack[ nnz_sp ] << 1;
               
               colIdxs[0] = nodes[ idxPtr + 1 ] + 1 + colIdxs[3];
               colIdxs[1] = nodes[ idxPtr + 0 ] + 1 + colIdxs[0];
               colIdxs[2] = nodes[ idxPtr + 3 ] + 1 + colIdxs[1];
               colIdxs[3] = nodes[ idxPtr + 2 ] + 1 + colIdxs[2];
               
               xVals[0] = x[ colIdxs[0] ];
               xVals[1] = x[ colIdxs[1] ];
               xVals[2] = x[ colIdxs[2] ];
               xVals[3] = x[ colIdxs[3] ];
               
               nnzVals[0] = d_nodes[ nnzPtr + 0 ];
               nnzVals[1] = d_nodes[ nnzPtr + 1 ];
               
               nnz_sp--;
               nnzPtr = nnzPtrStack[ nnz_sp ] << 1;
               nnzLvl = nnzLvlStack[ nnz_sp ];
               
               nnzVals[2] = d_nodes[ nnzPtr + 0 ];
               nnzVals[3] = d_nodes[ nnzPtr + 1 ];
               
               *y += xVals[0] * nnzVals[0];
               *y += xVals[1] * nnzVals[1];
               *y += xVals[2] * nnzVals[2];
               *y += xVals[3] * nnzVals[3];
            }
         
         }
         y++;
         rowCount++;
         rowBrkIdx++;
      }
   }
   clock_gettime( CLOCK_MONOTONIC, clks+1 );
   DEBUG_PRINT( "leaving SpMVFlatKernelCSR() " );
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void SpMVCOO( const U64 hgt, const U32 m, const U32 n, const U64 * nodes, const double * x, double * y, const U32 numRuns, timespec * clks ) {

   const bool hl0  = false;
   const bool hl2  = true;
   const bool hl4  = false;
   const bool hl8  = false;
   const bool hl16 = false;

   const U64 mask = 0xFFFFFFFF;
   const U32 nnzIdxR = mask & ( nodes[ nodes[1] ] >>  0 );
   const U32 nnzIdxL = mask & ( nodes[ nodes[1] ] >> 32 );
   const U32 rcaIdxR = mask & ( nodes[ nodes[2] ] >>  0 );
   const U32 rcaIdxL = mask & ( nodes[ nodes[2] ] >> 32 );

   // const U32 nnzIdxRR = mask & ( nodes[ nnzIdxR ] >>  0 );
   const U32 nnzIdxRL = mask & ( nodes[ nnzIdxR ] >> 32 );
   // const U32 rcaIdxRR = mask & ( nodes[ rcaIdxR ] >>  0 );
   const U32 rcaIdxRL = mask & ( nodes[ rcaIdxR ] >> 32 );
                                               
   const U32 nnzIdxLR = mask & ( nodes[ nnzIdxL ] >>  0 );
   const U32 nnzIdxLL = mask & ( nodes[ nnzIdxL ] >> 32 );
   const U32 rcaIdxLR = mask & ( nodes[ rcaIdxL ] >>  0 );
   const U32 rcaIdxLL = mask & ( nodes[ rcaIdxL ] >> 32 );

   // need 16 of these... 
   // const U32 nnzIdxRRR = mask & ( nodes[ nnzIdxRR ] >>  0 );
   // const U32 nnzIdxRRL = mask & ( nodes[ nnzIdxRR ] >> 32 );
   // const U32 rcaIdxRRR = mask & ( nodes[ rcaIdxRR ] >>  0 );
   // const U32 rcaIdxRRL = mask & ( nodes[ rcaIdxRR ] >> 32 );

   // const U32 nnzIdxRLR = mask & ( nodes[ nnzIdxRL ] >>  0 );
   const U32 nnzIdxRLL = mask & ( nodes[ nnzIdxRL ] >> 32 );
   // const U32 rcaIdxRLR = mask & ( nodes[ rcaIdxRL ] >>  0 );
   const U32 rcaIdxRLL = mask & ( nodes[ rcaIdxRL ] >> 32 );

   const U32 nnzIdxLRR = mask & ( nodes[ nnzIdxLR ] >>  0 );
   const U32 nnzIdxLRL = mask & ( nodes[ nnzIdxLR ] >> 32 );
   const U32 rcaIdxLRR = mask & ( nodes[ rcaIdxLR ] >>  0 );
   const U32 rcaIdxLRL = mask & ( nodes[ rcaIdxLR ] >> 32 );
                                               
   const U32 nnzIdxLLR = mask & ( nodes[ nnzIdxLL ] >>  0 );
   const U32 nnzIdxLLL = mask & ( nodes[ nnzIdxLL ] >> 32 );
   const U32 rcaIdxLLR = mask & ( nodes[ rcaIdxLL ] >>  0 );
   const U32 rcaIdxLLL = mask & ( nodes[ rcaIdxLL ] >> 32 );
   
   // need 32 of these...
   // const U32 nnzIdxRRRR = mask & ( nodes[ nnzIdxRRR ] >>  0 );
   // const U32 nnzIdxRRRL = mask & ( nodes[ nnzIdxRRR ] >> 32 );
   // const U32 rcaIdxRRRR = mask & ( nodes[ rcaIdxRRR ] >>  0 );
   // const U32 rcaIdxRRRL = mask & ( nodes[ rcaIdxRRR ] >> 32 );

   // const U32 nnzIdxRRLR = mask & ( nodes[ nnzIdxRRL ] >>  0 );
   // const U32 nnzIdxRRLL = mask & ( nodes[ nnzIdxRRL ] >> 32 );
   // const U32 rcaIdxRRLR = mask & ( nodes[ rcaIdxRRL ] >>  0 );
   // const U32 rcaIdxRRLL = mask & ( nodes[ rcaIdxRRL ] >> 32 );

   // const U32 nnzIdxRLRR = mask & ( nodes[ nnzIdxRLR ] >>  0 );
   // const U32 nnzIdxRLRL = mask & ( nodes[ nnzIdxRLR ] >> 32 );
   // const U32 rcaIdxRLRR = mask & ( nodes[ rcaIdxRLR ] >>  0 );
   // const U32 rcaIdxRLRL = mask & ( nodes[ rcaIdxRLR ] >> 32 );
                                               
   const U32 nnzIdxRLLR = mask & ( nodes[ nnzIdxRLL ] >>  0 );
   const U32 nnzIdxRLLL = mask & ( nodes[ nnzIdxRLL ] >> 32 );
   const U32 rcaIdxRLLR = mask & ( nodes[ rcaIdxRLL ] >>  0 );
   const U32 rcaIdxRLLL = mask & ( nodes[ rcaIdxRLL ] >> 32 );

   const U32 nnzIdxLRRR = mask & ( nodes[ nnzIdxLRR ] >>  0 );
   const U32 nnzIdxLRRL = mask & ( nodes[ nnzIdxLRR ] >> 32 );
   const U32 rcaIdxLRRR = mask & ( nodes[ rcaIdxLRR ] >>  0 );
   const U32 rcaIdxLRRL = mask & ( nodes[ rcaIdxLRR ] >> 32 );

   const U32 nnzIdxLRLR = mask & ( nodes[ nnzIdxLRL ] >>  0 );
   const U32 nnzIdxLRLL = mask & ( nodes[ nnzIdxLRL ] >> 32 );
   const U32 rcaIdxLRLR = mask & ( nodes[ rcaIdxLRL ] >>  0 );
   const U32 rcaIdxLRLL = mask & ( nodes[ rcaIdxLRL ] >> 32 );

   const U32 nnzIdxLLRR = mask & ( nodes[ nnzIdxLLR ] >>  0 );
   const U32 nnzIdxLLRL = mask & ( nodes[ nnzIdxLLR ] >> 32 );
   const U32 rcaIdxLLRR = mask & ( nodes[ rcaIdxLLR ] >>  0 );
   const U32 rcaIdxLLRL = mask & ( nodes[ rcaIdxLLR ] >> 32 );
                                               
   const U32 nnzIdxLLLR = mask & ( nodes[ nnzIdxLLL ] >>  0 );
   const U32 nnzIdxLLLL = mask & ( nodes[ nnzIdxLLL ] >> 32 );
   const U32 rcaIdxLLLR = mask & ( nodes[ rcaIdxLLL ] >>  0 );
   const U32 rcaIdxLLLL = mask & ( nodes[ rcaIdxLLL ] >> 32 );
   
   // need 64 of these ... gag
   // const U32 nnzIdxRRRRR = mask & ( nodes[ nnzIdxRRRR ] >>  0 );
   // const U32 nnzIdxRRRRL = mask & ( nodes[ nnzIdxRRRR ] >> 32 );
   // const U32 rcaIdxRRRRR = mask & ( nodes[ rcaIdxRRRR ] >>  0 );
   // const U32 rcaIdxRRRRL = mask & ( nodes[ rcaIdxRRRR ] >> 32 );
   // 
   // const U32 nnzIdxRRRLR = mask & ( nodes[ nnzIdxRRRL ] >>  0 );
   // const U32 nnzIdxRRRLL = mask & ( nodes[ nnzIdxRRRL ] >> 32 );
   // const U32 rcaIdxRRRLR = mask & ( nodes[ rcaIdxRRRL ] >>  0 );
   // const U32 rcaIdxRRRLL = mask & ( nodes[ rcaIdxRRRL ] >> 32 );
   // 
   // const U32 nnzIdxRRLRR = mask & ( nodes[ nnzIdxRRLR ] >>  0 );
   // const U32 nnzIdxRRLRL = mask & ( nodes[ nnzIdxRRLR ] >> 32 );
   // const U32 rcaIdxRRLRR = mask & ( nodes[ rcaIdxRRLR ] >>  0 );
   // const U32 rcaIdxRRLRL = mask & ( nodes[ rcaIdxRRLR ] >> 32 );
   //                                             
   // const U32 nnzIdxRRLLR = mask & ( nodes[ nnzIdxRRLL ] >>  0 );
   // const U32 nnzIdxRRLLL = mask & ( nodes[ nnzIdxRRLL ] >> 32 );
   // const U32 rcaIdxRRLLR = mask & ( nodes[ rcaIdxRRLL ] >>  0 );
   // const U32 rcaIdxRRLLL = mask & ( nodes[ rcaIdxRRLL ] >> 32 );
   // 
   // const U32 nnzIdxRLRRR = mask & ( nodes[ nnzIdxRLRR ] >>  0 );
   // const U32 nnzIdxRLRRL = mask & ( nodes[ nnzIdxRLRR ] >> 32 );
   // const U32 rcaIdxRLRRR = mask & ( nodes[ rcaIdxRLRR ] >>  0 );
   // const U32 rcaIdxRLRRL = mask & ( nodes[ rcaIdxRLRR ] >> 32 );
   // 
   // const U32 nnzIdxRLRLR = mask & ( nodes[ nnzIdxRLRL ] >>  0 );
   // const U32 nnzIdxRLRLL = mask & ( nodes[ nnzIdxRLRL ] >> 32 );
   // const U32 rcaIdxRLRLR = mask & ( nodes[ rcaIdxRLRL ] >>  0 );
   // const U32 rcaIdxRLRLL = mask & ( nodes[ rcaIdxRLRL ] >> 32 );
   // 
   // const U32 nnzIdxRLLRR = mask & ( nodes[ nnzIdxRLLR ] >>  0 );
   // const U32 nnzIdxRLLRL = mask & ( nodes[ nnzIdxRLLR ] >> 32 );
   // const U32 rcaIdxRLLRR = mask & ( nodes[ rcaIdxRLLR ] >>  0 );
   // const U32 rcaIdxRLLRL = mask & ( nodes[ rcaIdxRLLR ] >> 32 );
   //                                             
   // const U32 nnzIdxRLLLR = mask & ( nodes[ nnzIdxRLLL ] >>  0 );
   // const U32 nnzIdxRLLLL = mask & ( nodes[ nnzIdxRLLL ] >> 32 );
   // const U32 rcaIdxRLLLR = mask & ( nodes[ rcaIdxRLLL ] >>  0 );
   // const U32 rcaIdxRLLLL = mask & ( nodes[ rcaIdxRLLL ] >> 32 );

   const U32 nnzIdxLRRRR = mask & ( nodes[ nnzIdxLRRR ] >>  0 );
   const U32 nnzIdxLRRRL = mask & ( nodes[ nnzIdxLRRR ] >> 32 );
   const U32 rcaIdxLRRRR = mask & ( nodes[ rcaIdxLRRR ] >>  0 );
   const U32 rcaIdxLRRRL = mask & ( nodes[ rcaIdxLRRR ] >> 32 );

   const U32 nnzIdxLRRLR = mask & ( nodes[ nnzIdxLRRL ] >>  0 );
   const U32 nnzIdxLRRLL = mask & ( nodes[ nnzIdxLRRL ] >> 32 );
   const U32 rcaIdxLRRLR = mask & ( nodes[ rcaIdxLRRL ] >>  0 );
   const U32 rcaIdxLRRLL = mask & ( nodes[ rcaIdxLRRL ] >> 32 );

   const U32 nnzIdxLRLRR = mask & ( nodes[ nnzIdxLRLR ] >>  0 );
   const U32 nnzIdxLRLRL = mask & ( nodes[ nnzIdxLRLR ] >> 32 );
   const U32 rcaIdxLRLRR = mask & ( nodes[ rcaIdxLRLR ] >>  0 );
   const U32 rcaIdxLRLRL = mask & ( nodes[ rcaIdxLRLR ] >> 32 );
                                               
   const U32 nnzIdxLRLLR = mask & ( nodes[ nnzIdxLRLL ] >>  0 );
   const U32 nnzIdxLRLLL = mask & ( nodes[ nnzIdxLRLL ] >> 32 );
   const U32 rcaIdxLRLLR = mask & ( nodes[ rcaIdxLRLL ] >>  0 );
   const U32 rcaIdxLRLLL = mask & ( nodes[ rcaIdxLRLL ] >> 32 );

   const U32 nnzIdxLLRRR = mask & ( nodes[ nnzIdxLLRR ] >>  0 );
   const U32 nnzIdxLLRRL = mask & ( nodes[ nnzIdxLLRR ] >> 32 );
   const U32 rcaIdxLLRRR = mask & ( nodes[ rcaIdxLLRR ] >>  0 );
   const U32 rcaIdxLLRRL = mask & ( nodes[ rcaIdxLLRR ] >> 32 );

   const U32 nnzIdxLLRLR = mask & ( nodes[ nnzIdxLLRL ] >>  0 );
   const U32 nnzIdxLLRLL = mask & ( nodes[ nnzIdxLLRL ] >> 32 );
   const U32 rcaIdxLLRLR = mask & ( nodes[ rcaIdxLLRL ] >>  0 );
   const U32 rcaIdxLLRLL = mask & ( nodes[ rcaIdxLLRL ] >> 32 );

   const U32 nnzIdxLLLRR = mask & ( nodes[ nnzIdxLLLR ] >>  0 );
   const U32 nnzIdxLLLRL = mask & ( nodes[ nnzIdxLLLR ] >> 32 );
   const U32 rcaIdxLLLRR = mask & ( nodes[ rcaIdxLLLR ] >>  0 );
   const U32 rcaIdxLLLRL = mask & ( nodes[ rcaIdxLLLR ] >> 32 );
                                               
   const U32 nnzIdxLLLLR = mask & ( nodes[ nnzIdxLLLL ] >>  0 );
   const U32 nnzIdxLLLLL = mask & ( nodes[ nnzIdxLLLL ] >> 32 );
   const U32 rcaIdxLLLLR = mask & ( nodes[ rcaIdxLLLL ] >>  0 );
   const U32 rcaIdxLLLLL = mask & ( nodes[ rcaIdxLLLL ] >> 32 );

   if( true ) { assert( false ); }
   //
   // -- below code commented due to c++ cross compile issue -- 
   //
   // if( true ) {
   //    std::cout << std::endl;
   //    std::cout << "nnzIdxL = " << nnzIdxL<< std::endl;
   //    std::cout << "nnzIdxR = " << nnzIdxR<< std::endl;
   //    std::cout << "rcaIdxL = " << rcaIdxL<< std::endl;
   //    std::cout << "rcaIdxR = " << rcaIdxR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxLL = " << nnzIdxLL<< std::endl;
   //    std::cout << "nnzIdxLR = " << nnzIdxLR<< std::endl;
   //    std::cout << "rcaIdxLL = " << rcaIdxLL<< std::endl;
   //    std::cout << "rcaIdxLR = " << rcaIdxLR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxRL = " << nnzIdxRL<< std::endl;
   //    std::cout << "nnzIdxRR = " << nnzIdxRR<< std::endl;
   //    std::cout << "rcaIdxRL = " << rcaIdxRL<< std::endl;
   //    std::cout << "rcaIdxRR = " << rcaIdxRR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxLLL = " << nnzIdxLLL<< std::endl;
   //    std::cout << "nnzIdxLLR = " << nnzIdxLLR<< std::endl;
   //    std::cout << "rcaIdxLLL = " << rcaIdxLLL<< std::endl;
   //    std::cout << "rcaIdxLLR = " << rcaIdxLLR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxLRL = " << nnzIdxLRL<< std::endl;
   //    std::cout << "nnzIdxLRR = " << nnzIdxLRR<< std::endl;
   //    std::cout << "rcaIdxLRL = " << rcaIdxLRL<< std::endl;
   //    std::cout << "rcaIdxLRR = " << rcaIdxLRR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxRLL = " << nnzIdxRLL<< std::endl;
   //    std::cout << "nnzIdxRLR = " << nnzIdxRLR<< std::endl;
   //    std::cout << "rcaIdxRLL = " << rcaIdxRLL<< std::endl;
   //    std::cout << "rcaIdxRLR = " << rcaIdxRLR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxRRL = " << nnzIdxRRL<< std::endl;
   //    std::cout << "nnzIdxRRR = " << nnzIdxRRR<< std::endl;
   //    std::cout << "rcaIdxRRL = " << rcaIdxRRL<< std::endl;
   //    std::cout << "rcaIdxRRR = " << rcaIdxRRR<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "---------------------------"<< std::endl;
   //    std::cout << "nnzIdxRLLL = " << nnzIdxRLLL << std::endl;
   //    std::cout << "nnzIdxRLLR = " << nnzIdxRLLR << std::endl;
   //    std::cout << "rcaIdxRLRL = " << rcaIdxRLRL << std::endl;
   //    std::cout << "rcaIdxRLRR = " << rcaIdxRLRR << std::endl;
   //    std::cout << "nnzIdxRRLL = " << nnzIdxRRLL << std::endl;
   //    std::cout << "nnzIdxRRLR = " << nnzIdxRRLR << std::endl;
   //    std::cout << "rcaIdxRRRL = " << rcaIdxRRRL << std::endl;
   //    std::cout << "rcaIdxRRRR = " << rcaIdxRRRR << std::endl;
   //    std::cout << std::endl;
   // }

   if( hl0 ) {
      SpMVFlatKernelCOO_HL0( hgt - 1, nodes, nnzIdxL, rcaIdxL,
                                             x, y, clks );
      clks+=2;
   }
   if( hl2 ) {
      //SpMVFlatKernelCOO_HL2( hgt - 2, nodes, nnzIdxLL, rcaIdxLL,
      //                                       nnzIdxLR, rcaIdxLR,
      //                                       x, y, clks );
      //clks+=2;
      SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLLLL, rcaIdxLLLL,
                                             nnzIdxLLLR, rcaIdxLLLR,
                                             x, y, clks );
      clks+=2;
      SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLLRL, rcaIdxLLRL,
                                             nnzIdxLLRR, rcaIdxLLRR,
                                             x, y, clks );
      SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLRLL, rcaIdxLRLL,
                                             nnzIdxLRLR, rcaIdxLRLR,
                                             x, y, clks );
      SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLRRL, rcaIdxLRRL,
                                             nnzIdxLRRR, rcaIdxLRRR,
                                             x, y, clks );
      SpMVFlatKernelCOO_HL2_final( hgt - 4, nodes, nnzIdxRLLL, rcaIdxRLLL,
                                                   nnzIdxRLLR, rcaIdxRLLR,
                                                   x, y, clks );         
   }
   if( hl4 ) {
      SpMVFlatKernelCOO_HL4( hgt - 3, nodes, nnzIdxLLL, rcaIdxLLL,
                                             nnzIdxLLR, rcaIdxLLR,
                                             nnzIdxLRL, rcaIdxLRL,
                                             nnzIdxLRR, rcaIdxLRR,
                                             x, y, clks );
      clks+=2;
   }
   if( hl8 ) {
      SpMVFlatKernelCOO_HL8( hgt - 4, nodes, nnzIdxLLLL, rcaIdxLLLL,
                                             nnzIdxLLLR, rcaIdxLLLR,
                                             nnzIdxLLRL, rcaIdxLLRL,
                                             nnzIdxLLRR, rcaIdxLLRR,
                                             nnzIdxLRLL, rcaIdxLRLL,
                                             nnzIdxLRLR, rcaIdxLRLR,
                                             nnzIdxLRRL, rcaIdxLRRL,
                                             nnzIdxLRRR, rcaIdxLRRR,
                                             x, y, clks );
      clks+=2;
   }
   if( hl16 ) {
      SpMVFlatKernelCOO_HL16( hgt - 5, nodes, nnzIdxLLLLL, rcaIdxLLLLL,
                                              nnzIdxLLLLR, rcaIdxLLLLR,
                                              nnzIdxLLLRL, rcaIdxLLLRL,
                                              nnzIdxLLLRR, rcaIdxLLLRR,
                                              nnzIdxLLRLL, rcaIdxLLRLL,
                                              nnzIdxLLRLR, rcaIdxLLRLR,
                                              nnzIdxLLRRL, rcaIdxLLRRL,
                                              nnzIdxLLRRR, rcaIdxLLRRR,
                                              nnzIdxLRLLL, rcaIdxLRLLL,
                                              nnzIdxLRLLR, rcaIdxLRLLR,
                                              nnzIdxLRLRL, rcaIdxLRLRL,
                                              nnzIdxLRLRR, rcaIdxLRLRR,
                                              nnzIdxLRRLL, rcaIdxLRRLL,
                                              nnzIdxLRRLR, rcaIdxLRRLR,
                                              nnzIdxLRRRL, rcaIdxLRRRL,
                                              nnzIdxLRRRR, rcaIdxLRRRR,
                                              x, y, clks );
      clks+=2;
   }
   
   clks += 2;
   /*
   SpMVFlatKernelCOOHideLatency( hgt - 3, nodes, nnzIdxRLL, rcaIdxRLL,
                                                 nnzIdxRLR, rcaIdxRLR,
                                                 x, y, clks ); clks+=2;
   */
   //SpMVFlatKernelCOOHideLatency( hgt, nodes, nnzIdx10, rcaIdx10, nnzIdx11, rcaIdx11, x, y, clks ); clks+=2;
   //SpMVFlatKernelCOOHideLatency( hgt, nodes, nnzIdx00, rcaIdx00, nnzIdx01, rcaIdx01, x, y, clks ); clks+=2;
   ////SpMVFlatKernelCOOHideLatency( hgt, nodes, nnzIdx0, rcaIdx0, nnzIdx1, rcaIdx1, x, y, clks );
   ////SpMVFlatKernelCOO( hgt, nodes, x, y, clks );
   
   #ifdef __CHECK_SPMV_RESULT__
   PrintPTRVectorToMMFile( x, n, false, "x_coo.mtx" );
   PrintPTRVectorToMMFile( y, m, false, "y_coo.mtx" );
   #endif
   
   #ifdef __SPMV__
   U32 j = 0;
   
   // begin next spmv iter:
   while( true && j < numRuns ) {
      //SpMVFlatKernelCOO( hgt, nodes, x, y, clks + (j<<1) );
      //SpMVFlatKernelCOOHideLatency( hgt, nodes, nnzIdx0, rcaIdx0, nnzIdx1, rcaIdx1, x, y, clks + (j<<1) );

      if( hl0 ) {
         SpMVFlatKernelCOO_HL0( hgt - 1, nodes, nnzIdxL, rcaIdxL,
                                                x, y, clks );
         clks+=2;
      }
      if( hl2 ) {
         //SpMVFlatKernelCOO_HL2( hgt - 2, nodes, nnzIdxLL, rcaIdxLL,
         //                                       nnzIdxLR, rcaIdxLR,
         //                                       x, y, clks );
         //clks+=2;
         SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLLLL, rcaIdxLLLL,
                                                nnzIdxLLLR, rcaIdxLLLR,
                                                x, y, clks );
         clks+=2;
         SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLLRL, rcaIdxLLRL,
                                                nnzIdxLLRR, rcaIdxLLRR,
                                                x, y, clks );
         SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLRLL, rcaIdxLRLL,
                                                nnzIdxLRLR, rcaIdxLRLR,
                                                x, y, clks );
         SpMVFlatKernelCOO_HL2( hgt - 4, nodes, nnzIdxLRRL, rcaIdxLRRL,
                                                nnzIdxLRRR, rcaIdxLRRR,
                                                x, y, clks );
         SpMVFlatKernelCOO_HL2_final( hgt - 4, nodes, nnzIdxRLLL, rcaIdxRLLL,
                                                      nnzIdxRLLR, rcaIdxRLLR,
                                                      x, y, clks );         
      }      
      if( hl4 ) {
         SpMVFlatKernelCOO_HL4( hgt - 3, nodes, nnzIdxLLL, rcaIdxLLL,
                                                nnzIdxLLR, rcaIdxLLR,
                                                nnzIdxLRL, rcaIdxLRL,
                                                nnzIdxLRR, rcaIdxLRR,
                                                x, y, clks );
         clks+=2;
      }
      if( hl8 ) {
         SpMVFlatKernelCOO_HL8( hgt - 4, nodes, nnzIdxLLLL, rcaIdxLLLL,
                                                nnzIdxLLLR, rcaIdxLLLR,
                                                nnzIdxLLRL, rcaIdxLLRL,
                                                nnzIdxLLRR, rcaIdxLLRR,
                                                nnzIdxLRLL, rcaIdxLRLL,
                                                nnzIdxLRLR, rcaIdxLRLR,
                                                nnzIdxLRRL, rcaIdxLRRL,
                                                nnzIdxLRRR, rcaIdxLRRR,
                                                x, y, clks );
         clks+=2;
      }
      if( hl16 ) {
         SpMVFlatKernelCOO_HL16( hgt - 5, nodes, nnzIdxLLLLL, rcaIdxLLLLL,
                                                 nnzIdxLLLLR, rcaIdxLLLLR,
                                                 nnzIdxLLLRL, rcaIdxLLLRL,
                                                 nnzIdxLLLRR, rcaIdxLLLRR,
                                                 nnzIdxLLRLL, rcaIdxLLRLL,
                                                 nnzIdxLLRLR, rcaIdxLLRLR,
                                                 nnzIdxLLRRL, rcaIdxLLRRL,
                                                 nnzIdxLLRRR, rcaIdxLLRRR,
                                                 nnzIdxLRLLL, rcaIdxLRLLL,
                                                 nnzIdxLRLLR, rcaIdxLRLLR,
                                                 nnzIdxLRLRL, rcaIdxLRLRL,
                                                 nnzIdxLRLRR, rcaIdxLRLRR,
                                                 nnzIdxLRRLL, rcaIdxLRRLL,
                                                 nnzIdxLRRLR, rcaIdxLRRLR,
                                                 nnzIdxLRRRL, rcaIdxLRRRL,
                                                 nnzIdxLRRRR, rcaIdxLRRRR,
                                                 x, y, clks );
         clks+=2;
      }
      clks += 2;
      /*
      SpMVFlatKernelCOOHideLatency( hgt - 3, nodes, nnzIdxRLL, rcaIdxRLL,
                                                    nnzIdxRLR, rcaIdxRLR,
                                                    x, y, clks ); clks+=2;
      */
      j++;
   }
   #endif
}
void SpMVCSR( const U64 nnzHgt, const U64 idxHgt, const U64 ptrHgt, const U32 m, const U32 n, const U64 nnz, const U64 * nodes, const double * x, double * y, const U32 numRuns, timespec * clks ) {

   // const bool hl0  = true;
   // const bool hl2  = false;
   // const bool hl4  = false;
   // const bool hl8  = false;
   // const bool hl16 = false;

   const U64 mask = 0xFFFFFFFF;
   const U32 nnzValsRootNodePtr = mask & nodes[3];
   const U32 colIdxsRootNodePtr = mask & nodes[5];
   const U32 rowPtrsRootNodePtr = mask & nodes[7];
         
   SpMVFlatKernelCSR( nnz, m, nnzHgt-1, idxHgt-1, ptrHgt-1, nodes, nnzValsRootNodePtr, colIdxsRootNodePtr, rowPtrsRootNodePtr, x, y, clks );
   #ifdef __CHECK_SPMV_RESULT__
   PrintPTRVectorToMMFile( x, n, false, "x_csr.mtx" );
   PrintPTRVectorToMMFile( y, m, false, "y_csr.mtx" );
   #endif
   
   #ifdef __SPMV__
   U32 j = 0;
   // begin warm cache runs.
   while( j < numRuns ) {
      SpMVFlatKernelCSR( nnz, m, nnzHgt-1, idxHgt-1, ptrHgt-1, nodes, nnzValsRootNodePtr, colIdxsRootNodePtr, rowPtrsRootNodePtr, x, y, clks );
      clks += 2;
      j++;
   }
   #endif
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
